package com.quanyan.common.utils;

//import org.apache.commons.lang.ArrayUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * @author maoxian.liu
 *         工具类，用来计算经纬度于地址索引的光系
 */
public class PlaceTools {
    static double equator_size = 40076710; //地球赤道的长度  单位m
    static double latitude_scale = 0.006; //纬度方向的刻度
    static double longitude_scale = 0.006; //经度方向的刻度
    static double real_scale = equator_size * longitude_scale / 360; //格子的高度，米  格子的最小单位
    static double real_size = equator_size / 360; //一度多高 经度

    /**
     * 计算两个经纬度的距离平方
     *
     * @param lat1
     * @param lon1
     * @param lat2
     * @param lon2
     * @return
     */
    static public double calDistanceSquare(double lat1, double lon1, double lat2, double lon2) {
        double y = calDistanceSquare(lat1, lon1, lat2, lon2, calLandscapeSize(lat1));
        return y;
    }

    /**
     * 计算两个经纬度的距离平方,不用每次算经度上的刻度
     *
     * @param lat1
     * @param lon1
     * @param lat2
     * @param lon2
     * @param lon_size
     * @return
     */
    static public double calDistanceSquare(double lat1, double lon1, double lat2, double lon2, double lon_size) {
        double lat = (lat1 - lat2) * real_size;
        double lon = (lon1 - lon2) * lon_size;
        return lat * lat + lon * lon;
    }

    /**
     * 把纬度转换为0-180，南极为0
     *
     * @param latitude
     * @return
     */
    static public double convertLat(double latitude) {
        latitude = 90 + Math.abs(latitude);
        return latitude;
    }

    /**
     * 经度转换为0-360，西经是180-360
     *
     * @param longitude
     * @return
     */
    static public double convertLon(double longitude) {
        if (longitude < 0) longitude = 360 + longitude;
        return longitude;
    }

    /**
     * 计算指定经度和纬度所属格子的索引
     *
     * @param latitude  纬度
     * @param longitude 经度
     * @return
     */
    static public int calIndexByLatLon(double latitude, double longitude) {
        if (longitude == 0 || latitude == 0) {
            return 0;
        }
        longitude = convertLon(longitude);
        latitude = convertLat(latitude);
        int lat = (int) (latitude / latitude_scale);
        int lon = (int) (longitude / longitude_scale);
        lat = lat << 16;
        return lat ^ lon;
    }

    /**
     * 计算指定纬度下，单位纬度宽度
     *
     * @param latitude 纬度
     * @return
     */
    static public double calLandscapeSize(double latitude) {
        latitude = Math.abs(latitude);
        return real_size * Math.cos(latitude / 180 * Math.PI);
    }

    /**
     * 计算指定纬度下，格子在经度方向的宽度
     *
     * @param latitude 纬度
     * @return
     */
    static public double calLandscapeScale(double latitude) {
        latitude = Math.abs(latitude);
        return real_scale * Math.cos(latitude / 180 * Math.PI);
    }

    /**
     * 计算指定的范围跨越了哪些方块
     *
     * @param latitude
     * @param longitude
     * @param radius
     * @return 方块索引列表
     */
    static public Integer[] findIndex(double latitude, double longitude, int radius) {
        double lat_offset = radius / real_scale;
        double lon_offset = radius / calLandscapeScale(latitude);
        double lat = convertLat(latitude) / latitude_scale;
        double lon = convertLon(longitude) / longitude_scale;
        int lat_min = (int) (lat - lat_offset);
        int lat_max = (int) (lat + lat_offset);
        int lon_min = (int) (lon - lon_offset);
        int lon_max = (int) (lon + lon_offset);
        int index_size = (lat_max - lat_min + 1) * (lon_max - lon_min + 1);
        Integer[] indexs = new Integer[index_size];
        int i = 0;
        for (; lat_min <= lat_max; lat_min++) {
            for (int l = lon_min; l <= lon_max; l++) {
                indexs[i] = (lat_min << 16) ^ l;
                i++;
            }
        }
        return indexs;
    }


    /**
     * 计算指定的范围内的经纬度范围值
     *
     * @param latitude
     * @param longitude
     * @param radius
     * @return 该区间内经纬度的范围 map格式，经度39.9131750000,45.9131750000  纬度：116.5527340000，118.5527340000
     */
    static public Map findLatAndLngSection(double latitude, double longitude, int radius) {
        double lat_offset = radius / real_scale;
        double lon_offset = radius / calLandscapeScale(latitude);
        double lat = convertLat(latitude) / latitude_scale;
        double lon = convertLon(longitude) / longitude_scale;
        int lat_min = (int) (lat - lat_offset);
        int lat_max = (int) (lat + lat_offset);
        int lon_min = (int) (lon - lon_offset);
        int lon_max = (int) (lon + lon_offset);
            Map map = new HashMap();
            map.put("lng", lon_min+","+lon_max);
            map.put("lat", lat_min+","+lat_max);
        return map;

    }


    /**
     * 获得环形区域上的方格
     *
     * @param latitude
     * @param longitude
     * @param radiusMin
     * @param radiusMax
     * @return
     */
    static public Integer[] findIndex(double latitude, double longitude, int radiusMin, int radiusMax) {
        double lat_offset_min = radiusMin / real_scale;
        double lon_offset_min = radiusMin / calLandscapeScale(latitude);
        double lat_offset_max = radiusMax / real_scale;
        double lon_offset_max = radiusMax / calLandscapeScale(latitude);
        double lat = convertLat(latitude) / latitude_scale;
        double lon = convertLon(longitude) / longitude_scale;
        int lat_min = (int) (lat - lat_offset_max);
        int lat_max = (int) (lat + lat_offset_max);
        int lon_min = (int) (lon - lon_offset_max);
        int lon_max = (int) (lon + lon_offset_max);

        int lat_min_min = (int) (lat - lat_offset_min);
        int lat_min_max = (int) (lat + lat_offset_min);
        int lon_min_min = (int) (lon - lon_offset_min);
        int lon_min_max = (int) (lon + lon_offset_min);

        int index_size = (lat_max - lat_min + 1) * (lon_max - lon_min + 1)
                - (lat_min_max - lat_min_min + 1) * (lon_min_max - lon_min_min + 1);
        Integer[] indexs = new Integer[index_size];
        int i = 0;
        for (; lat_min <= lat_max; lat_min++) {
            for (int l = lon_min; l <= lon_max; l++) {
                if (lat_min_min <= lat_min && lat_min <= lat_min_max && lon_min_min <= l
                        && l <= lon_min_max)
                    continue;
                indexs[i] = (lat_min << 16) ^ l;
                i++;
            }
        }
        return indexs;
    }

    public static void main(String args[]) throws Exception {
        //System.out.println(calIndexByLatLon(36.456696, 115.985371));
//        Math.pow(calDistanceSquare(23.131826, 113.34360, 23.142422880494955, 113.28709430175786), 0.5);
//
//
//        System.out.println(calIndexByLatLon(39.9131750000, 116.5527340000));
//
//        System.out.println(calIndexByLatLon(39.9131060000, 116.5482560000));  //39.9131060000,116.5482560000
//
//        System.out.println(Math.sqrt(calDistanceSquare(39.9130570000, 116.5527700000, 39.9131060000, 116.5482560000)));
//
//        //测试格子索引数组
//        Integer[] indexArray = findIndex(39.9131750000, 116.5527340000, 10000);
//        for (int i=0;i < indexArray.length;i++) {
//            System.out.println("第" +i+ "个格子索引是：" + indexArray[i]);
//        }

        //System.out.println(calIndexByLatLon(36.456696, 115.985372));
        int n = -10;
//        System.out.println(10<<16);
//        System.out.println(10>>3);

//        System.out.println(Integer.toBinaryString(n));
//        System.out.println(n);
//        n = n >> 2;
//        System.out.println(Integer.toBinaryString(n));
//        System.out.println(n);
        double distance = PlaceTools.calDistanceSquare(22.545123, 113.959961, 22.543152827414765, 113.9604172528697);
        System.out.println(distance);
        System.out.println(Math.sqrt(distance));
    }
    //'36.456696', '115.985371', '398196736', '19330', '1381256066'


}
